/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.services.project;

import cn.easyplatform.dao.EntityDao;
import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.EntityInfo;
import cn.easyplatform.entities.beans.ResourceBean;
import cn.easyplatform.entities.transform.TransformerFactory;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.admin.CacheVo;
import cn.easyplatform.services.IEntityHandler;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.ModeType;
import cn.easyplatform.type.SubType;
import org.apache.shiro.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
class EntityHandlerImpl implements IEntityHandler {

    private static Logger log = LoggerFactory.getLogger(EntityHandlerImpl.class);

    private ProjectService ps;

    private Cache<Serializable, BaseEntity> cache;

    private boolean enabled;

    EntityHandlerImpl(ProjectService ps) {
        this.ps = ps;
        this.cache = ps.getCache("Entities");
        this.enabled = ps.getEntity().getMode() == ModeType.ONLINE;
        this.init(true);
    }

    @Override
    public void load() {
        if (enabled) {
            cache.clear();
            init(false);
        }
    }

    @Override
    public CacheVo load(String name) {
        if (enabled) {
            BaseEntity entity = getEntityById(name);
            if (entity == null)
                return null;
            cache.put(name, entity);
            return new CacheVo(entity.getId(), entity.getName(), entity.getDescription(), entity.getType());
        }
        return null;
    }

    @Override
    public List<CacheVo> getList() {
        if (enabled) {
            List<CacheVo> tmp = new ArrayList<CacheVo>(cache.size());
            for (BaseEntity entity : cache.values())
                tmp.add(new CacheVo(entity.getId(), entity.getName(), entity.getDescription(), entity.getType()));
            return tmp;
        }
        return Collections.emptyList();
    }

    private void init(boolean init) {
        EntityDao dao = ps.getEngineConfiguration().getEntityDao();
        if (init) {
            List<EntityInfo> entities = dao.getAllEntity(ps.getEntity().getEntityTableName());
            for (EntityInfo entity : entities) {
                try {
                    BaseEntity bean = TransformerFactory.newInstance()
                            .transformFromXml(entity);
                    // 启动背景任务
                    if (bean.getType().equals(EntityType.RESOURCE.getName())
                            && bean.getSubType().equals(SubType.JOB.getName())) {
                        ResourceBean rb = (ResourceBean) bean;
                        String immediate = rb.getProps().get("immediate");
                        if ((immediate == null || immediate
                                .equalsIgnoreCase("true"))
                                && !Strings
                                .isBlank(rb.getProps().get("expression")))
                            ps.getScheduleHandler().start(rb);
                    }
                    if (enabled)
                        cache.put(entity.getId(), bean);
                } catch (Exception e) {
                    if (log.isErrorEnabled())
                        log.error("load entity :" + entity.getId(), e);
                }
            }
            if (enabled)
                dao.updateEntity(ps.getEntity().getEntityTableName());
        } else if (enabled) {
            List<EntityInfo> entities = dao.getAllEntity(ps.getEntity().getEntityTableName());
            for (EntityInfo entity : entities) {
                BaseEntity bean = TransformerFactory.newInstance()
                        .transformFromXml(entity);
                cache.put(entity.getId(), bean);
            }
            dao.updateEntity(ps.getEntity().getEntityTableName());
        }
    }

    private <T extends BaseEntity> T getEntityById(String id) {
        EntityInfo e = ps.getEngineConfiguration().getEntityDao().getEntity(ps.getEntity().getEntityTableName(), id);
        if (e != null)
            return TransformerFactory.newInstance().transformFromXml(e);
        return null;
    }

    @Override
    public <T extends BaseEntity> List<T> getEntities(String type, String subType) {
        EntityDao dao = ps.getEngineConfiguration().getEntityDao();
        return dao.getEntities(ps.getEntity().getEntityTableName(), type, subType);
    }

    @Override
    public <T extends BaseEntity> T getEntity(String entityId) {
        if (!enabled)
            return getEntityById(entityId);
        try {
            T bean = (T) cache.get(entityId);
            if (bean == null) {
                bean = getEntityById(entityId);
                if (bean == null)
                    return null;
                cache.put(entityId, bean);
            }
            return bean;
        } catch (Exception ex) {
            if (log.isWarnEnabled())
                log.warn("getCache eid:" + entityId, ex);
            return null;
        }
    }

    @Override
    public void update(EntityInfo entity) {
        ps.getEngineConfiguration().getEntityDao().updateEntity(ps.getEntity().getEntityTableName(), entity);
        if (enabled) {
            BaseEntity bean = TransformerFactory.newInstance()
                    .transformFromXml(entity);
            cache.put(bean.getId(), bean);
        }
    }

    @Override
    public void remove(String entityId) {
        cache.remove(entityId);
    }

    void refresh() {
        if (enabled) {
            EntityDao dao = ps.getEngineConfiguration().getEntityDao();
            List<EntityInfo> entities = dao.getUpdatableEntity(ps.getEntity().getEntityTableName());
            if (!entities.isEmpty()) {
                for (final EntityInfo entity : entities) {
                    if (log.isDebugEnabled())
                        log.debug(
                                "update entity: Flag[{}] Id[{}],Name[{}]",
                                entity.getStatus(), entity.getId(),
                                entity.getName());
                    cache.remove(entity.getId());
                    BaseEntity bean = TransformerFactory.newInstance()
                            .transformFromXml(entity);
                    cache.put(bean.getId(), bean);
                }
                dao.updateEntity(ps.getEntity().getEntityTableName());
            }
        }
    }

    public void reset() {
        cache.clear();
    }

    public void destory() {
        cache.clear();
        ps.removeCache("Entities");
        cache = null;
    }

    @Override
    public void setEnabled(boolean enabled) {
        if (this.enabled != enabled) {
            this.enabled = enabled;
            if (!this.enabled)
                cache.clear();
        }
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }
}
